#pragma once
#include "public.hpp"
#include "Epoller.hpp"
#include "Connection.hpp"

class Reactor
{
    static const int EpollSetSize = 64;

private:
    unordered_map<int, Connection *> connections;
    Epoller epoller;

    struct epoll_event epollset[EpollSetSize];

public:
    Reactor()
    {
    }

    void set_WriteRead(int fd, bool readt, bool writet)
    {
        if(!IsExistConnection(fd)) return;

        uint32_t events = (readt ? EPOLLIN : 0) | (writet ? EPOLLOUT : 0)  | EPOLLET; 
        connections[fd]->setevents(events);
        epoller.mod_FdEvent(fd, events);
    }

    void RemoveConnection(int fd)
    {
        if(!IsExistConnection(fd)) return;

        //移除对fd的监管
        epoller.del_FdEvent(fd);
        //关闭sockfd
        connections[fd]->Close();
        //移除connection
        delete connections[fd];
        connections.erase(fd);
    }

    void AddConnection(int fd, uint32_t events, func_t recver, func_t sender, func_t execter)
    {
        // 1. 创建连接字段
        Connection *conn = new Connection(fd);
        conn->setevents(events);
        conn->setfunc(recver, sender, execter);
        conn->setReactor(this);

        // 2. 添加进连接集合
        connections.insert({fd, conn});

        // 3. 添加对fd的监听
        epoller.sup_FdEvent(fd, events);
    }

    void Dispatcher(int timeout)
    {
        while (true)
        {
            Looponce(timeout);
        }
    }

    bool IsExistConnection(int fd)
    {
        auto ret = connections.find(fd);
        return ret != connections.end();
    }

    void Looponce(int timeout)
    {
        // 获取就绪事件
        int n = epoller.wait(EpollSetSize, epollset, timeout);
        for (int i = 0; i < n; i++)
        {
            int fd = epollset[i].data.fd;
            uint32_t events = epollset[i].events;

            if ((events | EPOLLHUP) || (events | EPOLLERR))
                events |= EPOLLIN | EPOLLOUT;
            if (events | EPOLLIN)
            {
                if (IsExistConnection(fd) && connections[fd]->_recver != nullptr)
                {
                    connections[fd]->_recver(connections[fd]);
                }
            }
            else if (events | EPOLLOUT)
            {
                if (IsExistConnection(fd) && connections[fd]->_sender != nullptr)
                {
                    connections[fd]->_sender(connections[fd]);
                }
            }
        }
    }

    ~Reactor()
    {
    }
};
